﻿using System;
using System.Collections.Generic;
using Lucene.Net.Analysis;
using Lucene.Net.Index;
using Lucene.Net.Documents;
using System.Reflection;
using Lucene.Net.QueryParsers;
using Lucene.Net.Search;
using System.Threading.Tasks;
using System.Data;

namespace LuceneNet
{
    /// <summary>
    /// 盘古分词在lucene.net中的使用帮助类
    /// 调用PanGuLuceneHelper.instance
    /// </summary>
    public class PanGuLuceneHelper
    {
        /// <summary>
        /// 修改数据库事件
        /// </summary>
        /// <param name="id"></param>
        /// <param name="Name"></param>
        public delegate void UpdateSqlEvent(int id, string Name);
        public event UpdateSqlEvent UpdateSql;

        private PanGuLuceneHelper() { }

        #region 单一实例

        /// <summary>
        /// PanGuLuceneHelper对象
        /// </summary>
        private static PanGuLuceneHelper _instance = null;

        /// <summary>
        /// PanGuLuceneHelper对象初始化
        /// </summary>
        public static PanGuLuceneHelper instance
        {
            get
            {
                if (_instance == null) _instance = new PanGuLuceneHelper();
                return _instance;
            }
        }

        #endregion

        #region 分词

        /// <summary>
        /// 分词
        /// </summary>
        /// <param name="keyword">关键字</param>
        /// <returns></returns>
        public string[] SplitWords(string keyword)
        {
            List<string> strList = new List<string>();
            System.IO.StringReader reader = new System.IO.StringReader(keyword);
            Lucene.Net.Analysis.TokenStream ts = analyzer.TokenStream(keyword, reader);
            bool hasNext = ts.IncrementToken();
            Lucene.Net.Analysis.Tokenattributes.ITermAttribute ita;
            while (hasNext)
            {
                ita = ts.GetAttribute<Lucene.Net.Analysis.Tokenattributes.ITermAttribute>();
                strList.Add(ita.Term);
                hasNext = ts.IncrementToken();
            }
            ts.CloneAttributes();
            reader.Close();
            analyzer.Close();
            return strList.ToArray();
        }

        #endregion

        #region 创建索引

        /// <summary>
        /// 创建索引
        /// </summary>
        /// <param name="datalist">数据列表</param>
        /// <returns></returns>
        public bool CreateIndex<T>(List<T> t, string[] fileds)
        {
            IndexWriter writer = null;
            try
            {
                writer = new IndexWriter(directory_luce, analyzer, false, IndexWriter.MaxFieldLength.LIMITED);//false表示追加（true表示删除之前的重新写入）
            }
            catch
            {
                writer = new IndexWriter(directory_luce, analyzer, true, IndexWriter.MaxFieldLength.LIMITED);//false表示追加（true表示删除之前的重新写入）
            }
            foreach (var data in t)
            {
                CreateIndex(writer, data, fileds);
            }
            writer.Optimize();
            writer.Dispose();
            return true;
        }

        /// <summary>
        /// 创建索引
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="writer"></param>
        /// <param name="t"></param>
        /// <returns></returns>
        public bool CreateIndex<T>(IndexWriter writer, T t, string[] fileds)
        {
            try
            {
                if (t == null) return false;
                Document doc = new Document();
                Type type = t.GetType();//assembly.GetType("Reflect_test.PurchaseOrderHeadManageModel", true, true); //命名空间名称 + 类名    

                //创建类的实例    
                //object obj = Activator.CreateInstance(type, true);  
                //获取公共属性    
                PropertyInfo[] Propertys = type.GetProperties();
                Term term = new Term("Id");
                int id = 0;

                PropertyInfo pi;
                string name;
                object objval;
                string value; //值

                for (int i = 0; i < Propertys.Length; i++)
                {
                    //Propertys[i].SetValue(Propertys[i], i, null); //设置值
                    pi = Propertys[i];
                    name = pi.Name.ToLower();
                    objval = pi.GetValue(t, null);
                    value = objval == null ? "" : objval.ToString(); //值
                    foreach (var item in fileds)
                    {
                        if (name == "id" && name == item.ToLower())//id在写入索引时必是不分词，否则是模糊搜索和删除，会出现混乱
                        {
                            doc.Add(new Field(name, value, Field.Store.YES, Field.Index.NOT_ANALYZED));//id不分词
                            id = Convert.ToInt32(value);
                            term = term.CreateTerm(value);
                        }
                        else if (name == item.ToLower())//指定字段做索引
                        {
                            doc.Add(new Field(name, value, Field.Store.YES, Field.Index.ANALYZED));
                        }
                    }

                }
                writer.UpdateDocument(term, doc);
                //修改Sql状态为创建索引
                UpdateSql?.Invoke(id, type.Name);
            }
            catch (System.IO.FileNotFoundException fnfe)
            {
                throw fnfe;
            }
            return true;
        }

        #endregion

        #region 查询数据(分页)

        /// <summary>
        /// List查询数据(分页)
        /// </summary>
        /// <param name="keyword">关键字</param>
        /// <param name="fileds">查询字段</param>
        /// <param name="PageIndex">当前页码</param>
        /// <param name="PageSize">页面条数</param>
        /// <param name="TotalCount">总记录数</param>
        /// <returns></returns>
        public List<T> Search<T>(string keyword, string[] fileds, int PageIndex, int PageSize, out int TotalCount) where T : new()
        {
            if (PageIndex < 1) PageIndex = 1;
            QueryParser parser = null;// new QueryParser(version, field, analyzer);//一个字段查询
            parser = new MultiFieldQueryParser(version, fileds, analyzer);//多个字段查询
            keyword = keyword.Replace("?", "").Replace("*", "").Replace("？", "");
            Query queryKeyword = parser.Parse(keyword);
            TopScoreDocCollector collector = TopScoreDocCollector.Create(PageIndex * PageSize, false);
            IndexSearcher searcher = new IndexSearcher(directory_luce, true);//true-表示只读
            searcher.Search(queryKeyword, collector);
            if (collector == null || collector.TotalHits == 0)
            {
                TotalCount = 0;
                return null;
            }
            else
            {
                int start = PageSize * (PageIndex - 1);
                //结束数
                int limit = PageSize;
                ScoreDoc[] hits = collector.TopDocs(start, limit).ScoreDocs;
                List<T> list = new List<T>();
                TotalCount = collector.TotalHits;
                foreach (ScoreDoc sd in hits)//遍历搜索到的结果
                {
                    try
                    {
                        T t = new T();
                        Type type = t.GetType();
                        //获取公共属性    
                        PropertyInfo[] Propertys = type.GetProperties();
                        for (int i = 0; i < Propertys.Length; i++)
                        {
                            PropertyInfo pi = Propertys[i];
                            string name = pi.Name.ToLower();
                            Document doc = searcher.Doc(sd.Doc);
                            switch (pi.PropertyType.Name)
                            {
                                case "Int32":
                                    pi.SetValue(t, Convert.ToInt32(doc.Get(name)));
                                    break;
                                case "Int64":
                                    pi.SetValue(t, Convert.ToInt64(doc.Get(name)));
                                    break;
                                case "Double":
                                    pi.SetValue(t, Convert.ToDouble(doc.Get(name)));
                                    break;
                                case "Decimal":
                                    pi.SetValue(t, Convert.ToDecimal(doc.Get(name)));
                                    break;
                                case "Char":
                                    pi.SetValue(t, Convert.ToChar(doc.Get(name)));
                                    break;
                                case "Boolean":
                                    pi.SetValue(t, Convert.ToBoolean(doc.Get(name)));
                                    break;
                                case "String":
                                    pi.SetValue(t, Convert.ToString(doc.Get(name)));
                                    break;
                                case "DateTime":
                                    pi.SetValue(t, Convert.ToDateTime(doc.Get(name)));
                                    break;
                            }
                        }
                        list.Add(t);
                    }
                    catch (Exception ex)
                    {
                    }
                }
                return list;
            }
        }


        /// <summary>
        /// DataTable查询数据(分页)
        /// </summary>
        /// <param name="keyword">关键字</param>
        /// <param name="fileds">查询字段</param>
        /// <param name="PageIndex">当前页码</param>
        /// <param name="PageSize">页面条数</param>
        /// <param name="TotalCount">总记录数</param>
        /// <returns></returns>
        public void Search(string keyword, string[] fileds, int PageIndex, int PageSize, out int TotalCount, ref DataTable dt)
        {
            if (PageIndex < 1) PageIndex = 1;
            QueryParser parser = null;// new QueryParser(version, field, analyzer);//一个字段查询
            parser = new MultiFieldQueryParser(version, fileds, analyzer);//多个字段查询
            Query queryKeyword = parser.Parse(keyword);

            TopScoreDocCollector collector = TopScoreDocCollector.Create(PageIndex * PageSize, false);
            IndexSearcher searcher = new IndexSearcher(directory_luce, true);//true-表示只读
            searcher.Search(queryKeyword, collector);
            if (collector == null || collector.TotalHits == 0)
            {
                TotalCount = 0;
            }
            else
            {
                int start = PageSize * (PageIndex - 1);
                //结束数
                int limit = PageSize;
                ScoreDoc[] hits = collector.TopDocs(start, limit).ScoreDocs;

                TotalCount = collector.TotalHits;
                DataRow dr;
                Document doc;
                foreach (ScoreDoc sd in hits)//遍历搜索到的结果
                {
                    dr = dt.NewRow();
                    foreach (DataColumn dc in dt.Columns)
                    {
                        try
                        {
                            doc = searcher.Doc(sd.Doc);
                            string name = dc.ColumnName.ToLower();
                            dr[dc.ColumnName] = doc.Get(name);
                        }
                        catch (Exception ex)
                        {

                        }
                    }
                    dt.Rows.Add(dr);
                }
            }
        }

        #endregion

        #region 删除索引数据（根据key）

        /// <summary>
        /// 删除索引数据（根据key）
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool Delete(string key, string fieldName)
        {
            bool IsSuccess = false;
            Term term = new Term(fieldName, key);
            IndexWriter writer = new IndexWriter(directory_luce, analyzer, false, IndexWriter.MaxFieldLength.LIMITED);
            writer.DeleteDocuments(term);
            writer.Commit();
            IsSuccess = writer.HasDeletions();
            writer.Dispose();
            return IsSuccess;
        }

        #endregion

        #region 删除全部索引数据

        /// <summary>
        /// 删除全部索引数据
        /// </summary>
        /// <returns></returns>
        public bool DeleteAll()
        {
            bool IsSuccess = true;
            try
            {
                IndexWriter writer = new IndexWriter(directory_luce, analyzer, false, IndexWriter.MaxFieldLength.LIMITED);
                writer.DeleteAll();
                writer.Commit();
                //writer.Optimize();//
                IsSuccess = writer.HasDeletions();
                writer.Dispose();
            }
            catch
            {
                IsSuccess = false;
            }
            return IsSuccess;
        }

        #endregion

        #region directory_luce

        /// <summary>
        /// Lucence目录
        /// </summary>
        private Lucene.Net.Store.Directory _directory_luce = null;

        /// <summary>
        /// Lucene.Net的目录-参数
        /// </summary>
        public Lucene.Net.Store.Directory directory_luce
        {
            get
            {
                if (_directory_luce == null) _directory_luce = Lucene.Net.Store.FSDirectory.Open(directory);
                return _directory_luce;
            }
        }

        #endregion

        #region directory

        /// <summary>
        /// Lucence目录
        /// </summary>
        private System.IO.DirectoryInfo _directory = null;

        /// <summary>
        /// 索引在硬盘上的目录
        /// </summary>
        public System.IO.DirectoryInfo directory
        {
            get
            {
                if (_directory == null)
                {
                    string dirPath = Utility.GetValue(Utility.GetConfig("LuceneData"), "");
                    if (System.IO.Directory.Exists(dirPath) == false) _directory = System.IO.Directory.CreateDirectory(dirPath);
                    else _directory = new System.IO.DirectoryInfo(dirPath);
                }
                return _directory;
            }
        }

        #endregion

        #region 分析器

        /// <summary>
        /// 分析仪
        /// </summary>
        private Analyzer _analyzer = null;

        /// <summary>
        /// 分析器
        /// </summary>
        public Analyzer analyzer
        {
            get
            {
                if (_analyzer == null)
                {
                    _analyzer = new Lucene.Net.Analysis.PanGu.PanGuAnalyzer();//
                    //_analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30);
                }
                return _analyzer;
            }
        }

        #endregion

        #region 版本

        /// <summary>
        /// 版本
        /// </summary>
        private static Lucene.Net.Util.Version _version = Lucene.Net.Util.Version.LUCENE_30;

        /// <summary>
        /// 版本号枚举类
        /// </summary>
        public Lucene.Net.Util.Version version
        {
            get
            {
                return _version;
            }
        }

        #endregion
    }
}